package internal

import (
	"os"
	"path/filepath"
	"sync"
	"time"
)

// Cutter 实现 io.Writer 接口
// 用于日志切割, strings.Join([]string{director,layout, formats..., level+".log"}, os.PathSeparator)
type Cutter struct {
	level    string        // 日志级别(debug, info, warn, error, dpanic, panic, fatal)
	layout   string        // 时间格式 2006-01-02 15:04:05
	formats  []string      // 自定义参数([]string{Director,"2006-01-02", "business"(此参数可不写), level+".log"}
	director string        // 日志文件夹
	file     *os.File      // 文件句柄
	mutex    *sync.RWMutex // 读写锁
}

type CutterOption func(*Cutter)

// CutterWithLayout 时间格式
func CutterWithLayout(layout string) CutterOption {
	return func(c *Cutter) {
		c.layout = layout
	}
}

// CutterWithFormats 格式化参数
func CutterWithFormats(format ...string) CutterOption {
	return func(c *Cutter) {
		if len(format) > 0 {
			c.formats = format
		}
	}
}

func NewCutter(director string, level string, options ...CutterOption) *Cutter {
	rotate := &Cutter{
		level:    level,
		director: director,
		mutex:    new(sync.RWMutex),
	}
	for i := 0; i < len(options); i++ {
		options[i](rotate)
	}
	return rotate
}

func (c *Cutter) Write(bytes []byte) (n int, err error) {
	c.mutex.Lock() // 加锁
	defer func() {
		if c.file != nil {
			_ = c.file.Close() // 关闭文件
			c.file = nil
		}
		c.mutex.Unlock() // 释放锁
	}()
	length := len(c.formats)
	values := make([]string, 0, 3+length)
	values = append(values, c.director)
	if c.layout != "" {
		values = append(values, time.Now().Format(c.layout))
	}
	for i := 0; i < length; i++ {
		values = append(values, c.formats[i])
	}
	values = append(values, c.level+".log")
	filename := filepath.Join(values...) // 将values切片中的所有路径元素连接成一个完整的路径
	director := filepath.Dir(filename)   // 获取filename变量表示的路径的目录部分
	// 使用os.MkdirAll函数创建director变量表示的目录，以及所有必要的父目录。
	// os.ModePerm是一个常量，表示目录的权限为0777（所有用户都有读写执行权限）
	err = os.MkdirAll(director, os.ModePerm)
	if err != nil {
		return 0, err
	}
	// 这是一个位掩码，表示文件的打开模式。
	// os.O_CREATE表示如果文件不存在，则创建该文件；os.O_APPEND表示如果文件存在，则将数据追加到文件末尾；os.O_WRONLY表示以只写模式打开文件。
	// 0644：这是一个八进制数，表示文件的权限。在这个例子中，文件的所有者有读写权限，而组用户和其他用户只有读权限
	c.file, err = os.OpenFile(filename, os.O_CREATE|os.O_APPEND|os.O_WRONLY, 0644)
	if err != nil {
		return 0, err
	}
	return c.file.Write(bytes)
}
